using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using WindowsPhoneGame1.LevelItems;
using AssetXMLBuilder;
using WindowsPhoneGame1.Shapes;
using Microsoft.Xna.Framework.Input.Touch;
using WindowsPhoneGame1.GamePlayStates;
using WindowsPhoneGame1.GameScreens;
using WindowsPhoneGame1.Collisions;

namespace WindowsPhoneGame1
{
    public class Level
    {
        protected Game1 game;

        protected Texture2D background4;
        protected Texture2D background3;
        protected Texture2D[] background2;
        protected float[] background2positions;
        protected Texture2D background1;
        protected LevelItem[] track = new LevelItem[0];
        protected Texture2D foreground;

        protected int worldNr, levelNr;

        protected Car car;
        protected PointF start, finish;

        protected GamePlayState state;

        protected CollisionManager collisionManager;

        public GamePlayState GamePlayState
        {
            get
            {
                return state;
            }
            set
            {
                if (state != null)
                    state.UnloadContent();
                state = value;
                state.Initialize();
                state.LoadContent();
            }
        }

        public Level(Game1 game, int worldNr, int levelNr)
        {
            this.game = game;
            this.worldNr = worldNr;
            this.levelNr = levelNr;

            collisionManager = new CollisionManager(this);

            GamePlayState = new StartState(game, this);
        }

        public void Initialize()
        {
            // debug
            worldNr = 0;
            state.Initialize();
        }

        public void LoadContent()
        {
            background1 = game.Content.Load<Texture2D>("images/world" + worldNr + "/background1");
            background2 = new Texture2D[2];
            background2[0] = game.Content.Load<Texture2D>("images/world" + worldNr + "/background2_1");
            background2[1] = game.Content.Load<Texture2D>("images/world" + worldNr + "/background2_2");
            background2positions = new float[2] { 0, background2[0].Bounds.Width };
            background3 = game.Content.Load<Texture2D>("images/world" + worldNr + "/background3");
            background4 = game.Content.Load<Texture2D>("images/world" + worldNr + "/background4");
            foreground = game.Content.Load<Texture2D>("images/world" + worldNr + "/foreground");

            LoadTrackItems();
            LoadFlagItems();
            LoadCar();

            state.LoadContent();
        }

        private void LoadTrackItems()
        {
            List<LevelItem> list = new List<LevelItem>();
            list = track.ToList<LevelItem>();

            // loading track items
            TrackItemTemplate[] trackItemTemplates =
                game.Content.Load<TrackItemTemplate[]>("levels/level" + levelNr + "track");
            
            foreach (TrackItemTemplate template in trackItemTemplates)
            {
                string[] pointStrings = template.Points.Split(' ');
                Shapes.PointF[] points = new Shapes.PointF[pointStrings.Length];

                for (int i = 0; i < points.Length; i++)
                {
                    string[] xy;
                    xy = pointStrings[i].Split(',');
                    int x, y; 
                    int.TryParse(xy[0], out x);
                    int.TryParse(xy[1], out y);
                    points[i] = new Shapes.PointF(x, y);
                }

                TrackItem item = new TrackItem(
                    new Shapes.PointF(template.PositionX, template.PositionY),
                    new Polygon(points),
                    game.Content.Load<Texture2D>(template.TexturePath));
                list.Add(item);
            }
            
            track = list.ToArray();
        }

        private void LoadFlagItems()
        {
            List<LevelItem> list = new List<LevelItem>();
            list = track.ToList<LevelItem>();

            // loading track items
            FlagItemTemplate[] flagItemTemplates =
                game.Content.Load<FlagItemTemplate[]>("levels/level" + levelNr + "flags");

            foreach (FlagItemTemplate template in flagItemTemplates)
            {
                string[] pointStrings = template.Points.Split(' ');
                Shapes.PointF[] points = new Shapes.PointF[pointStrings.Length];

                for (int i = 0; i < points.Length; i++)
                {
                    string[] xy;
                    xy = pointStrings[i].Split(',');
                    int x, y;
                    int.TryParse(xy[0], out x);
                    int.TryParse(xy[1], out y);
                    points[i] = new Shapes.PointF(x, y);
                }

                FlagItem item = new FlagItem(
                    new Shapes.PointF(template.PositionX, template.PositionY),
                    new Polygon(points),
                    game.Content.Load<Texture2D>(template.TexturePath));
                list.Add(item);
            }

            start = list.ElementAt(list.Count - 3).Position;
            finish = list.ElementAt(list.Count - 1).Position;

            track = list.ToArray();
        }

        private void LoadCar()
        {
            CarTemplate carTemplate =
                game.Content.Load<CarTemplate>("cars/Car1");

            Texture2D chassisTexture = game.Content.Load<Texture2D>(carTemplate.ChassisFilePath);

            car = new Car(carTemplate.Name, start,
                chassisTexture,
                game.Content.Load<Texture2D>(carTemplate.WheelFilePath),
                carTemplate.FrontWheelPos, carTemplate.RearWheelPos);
        }

        public void UnloadContent()
        {
            state.UnloadContent();
        }

        public void Update(GameTime gameTime)
        {
            if (!state.pause)
            {

                car.Update(gameTime);
                collisionManager.Update(gameTime);

                if (!(state is FinishState))
                {
                    if (car.Position.X > finish.X)
                        GamePlayState = new FinishState(game, this);

                    while (TouchPanel.IsGestureAvailable)
                    {
                        GestureSample gesture = TouchPanel.ReadGesture();

                        switch (gesture.GestureType)
                        {
                            case GestureType.Tap:
                                car.ShiftGearUp();
                                break;
                            case GestureType.Hold:
                                car.Break();
                                break;
                        }
                    }
                }
            }
            state.Update(gameTime);
        }

        public void Draw(GameTime gameTime)
        {
            float screenWidth = game.GraphicsDevice.Viewport.Width;
            float screenHeight = game.GraphicsDevice.Viewport.Height;

            DrawParallax(background4,    3, 0, 50, true);
            DrawParallax(background2[0], 2, background2positions[0], screenHeight - 100 - background2[0].Bounds.Height, false);
            DrawParallax(background2[1], 2, background2positions[1], screenHeight - 100 - background2[1].Bounds.Height, false);
            DrawParallax(background3,    1, 0, 75, true);
            DrawParallax(background1,    0, 0, screenHeight - 100 - background1.Bounds.Height, true);

            foreach (LevelItem item in track)
            {
                item.Draw(gameTime, car.Position, game);
            }

            car.Draw(gameTime, car.Position, game);

            DrawParallax(foreground,    -1, 0, screenHeight - 100, true);
            DrawParallax(foreground,    -2, 0, screenHeight - 66, true);
            DrawParallax(foreground,    -3, 0, screenHeight - 33, true);


            state.Draw(gameTime);
        }

        public void DrawParallax(Texture2D texture, int layer, float x, float y, bool repeated)
        {
            float pos = x - car.Position.X / (float)Math.Pow(2, layer);
            
            if(repeated)
                pos %= texture.Bounds.Width;

            if (repeated)
            {
                if(pos > 0)
                    game.SpriteBatch.Draw(texture, new Vector2(pos - texture.Bounds.Width, y), Color.White);

                while (pos < game.GraphicsDevice.Viewport.Width)
                {
                    game.SpriteBatch.Draw(texture, new Vector2(pos, y), Color.White);
                    pos += texture.Bounds.Width;
                }
            }
            else
                game.SpriteBatch.Draw(texture, new Vector2(pos, y), Color.White);
        }

        public Car GetCar()
        {
            return car;
        }

        internal void ReturnToLevelSelect()
        {
            game.SetScreen(new LevelSelectScreen(game, worldNr));
        }

        public LevelItem[] GetTrackItems()
        {
            return track;
        }
    }
}
